﻿using Serilog;
using Serilog.Events;
using Serilog.Exceptions;
using Serilog.Formatting.Compact;
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;

namespace Chaunce.FrameWork.NetCore.Chaunce.Logging
{
    /// <summary>
    /// serilog日志封装
    /// </summary>
    public class ChaunceSerilog
    {
        /// <summary>
        /// 初始化Serilog.接收器支持console、file、debug、exceptionless(推荐),并且可以同时包含多种接收器.
        /// </summary>
        /// <param name="param">初始化参数</param>
        public static void InitSerilog(ChaunceSerilogSetting param)
        {
            var configuraton = new LoggerConfiguration()
                .Enrich.FromLogContext()//显示自定义属性
                 .Enrich.WithExceptionDetails();//异常显示明细信息

            if (param.Configuration != null)
            {
                configuraton = configuraton.ReadFrom.Configuration(param.Configuration);
            }

            switch (param.MinimumLevel)
            {
                case LogEventLevel.Debug:
                    configuraton = configuraton.MinimumLevel.Debug();
                    break;
                case LogEventLevel.Error:
                    configuraton = configuraton.MinimumLevel.Error();
                    break;
                case LogEventLevel.Fatal:
                    configuraton = configuraton.MinimumLevel.Fatal();
                    break;
                case LogEventLevel.Information:
                    configuraton = configuraton.MinimumLevel.Information();
                    break;
                case LogEventLevel.Verbose:
                    configuraton = configuraton.MinimumLevel.Verbose();
                    break;
                case LogEventLevel.Warning:
                    configuraton = configuraton.MinimumLevel.Warning();
                    break;
            }
            if (!string.IsNullOrWhiteSpace(param.ApplicationName))
            {
                configuraton = configuraton.Enrich.WithProperty("Application", param.ApplicationName);
            }

            var sinks = param.Sinks;
            if (sinks != null)
            {
                if (sinks.Contains(SerilogSink.Console))
                {
                    configuraton = configuraton.WriteTo.Console();
                }
                if (sinks.Contains(SerilogSink.Debug))
                {
                    configuraton = configuraton.WriteTo.Debug();
                }
                if (sinks.Contains(SerilogSink.File))
                {
                    if (param.IsSeparateLogFile)
                    {
                        configuraton = configuraton.WriteTo.Logger(lc => lc.Filter.ByIncludingOnly(evt => evt.Level == LogEventLevel.Error)
                          .WriteTo.File(new CompactJsonFormatter(), "logs\\log_error.txt",
                         rollingInterval: RollingInterval.Day,
                         rollOnFileSizeLimit: true))
                          .WriteTo.Logger(lc => lc.Filter.ByIncludingOnly(evt => evt.Level == LogEventLevel.Warning)
                          .WriteTo.File(new CompactJsonFormatter(), "logs\\log_warning.txt",
                         rollingInterval: RollingInterval.Day,
                         rollOnFileSizeLimit: true))
                          .WriteTo.Logger(lc => lc.Filter.ByIncludingOnly(evt => evt.Level == LogEventLevel.Fatal)
                          .WriteTo.File(new CompactJsonFormatter(), "logs\\log_fatal.txt",
                         rollingInterval: RollingInterval.Day,
                         rollOnFileSizeLimit: true))
                          .WriteTo.Logger(lc => lc.Filter.ByIncludingOnly(evt => evt.Level == LogEventLevel.Information)
                          .WriteTo.File(new CompactJsonFormatter(), "logs\\log_info.txt",
                         rollingInterval: RollingInterval.Day,
                         rollOnFileSizeLimit: true))
                          .WriteTo.Logger(lc => lc.Filter.ByIncludingOnly(evt => evt.Level == LogEventLevel.Verbose)
                          .WriteTo.File(new CompactJsonFormatter(), "logs\\log_verbose.txt",
                         rollingInterval: RollingInterval.Day,
                         rollOnFileSizeLimit: true))
                         .WriteTo.Logger(lc => lc.Filter.ByIncludingOnly(evt => evt.Level == LogEventLevel.Debug)
                          .WriteTo.File(new CompactJsonFormatter(), "logs\\log_debug.txt",
                         rollingInterval: RollingInterval.Day,
                         rollOnFileSizeLimit: true));
                    }
                    else
                    {
                        configuraton = configuraton.WriteTo.File(new CompactJsonFormatter(), "logs\\log.txt",
                       rollingInterval: RollingInterval.Day,
                       rollOnFileSizeLimit: true);
                    }
                }
                if (sinks.Contains(SerilogSink.Exceptionless))
                {
                    var elSetting = param.ExceptionLessSetting;
                    if (elSetting == null)
                    {
                        throw new ArgumentNullException("ExceptionLessSetting参数不能为空");
                    }
                    var apiKey = elSetting.ApiKey;
                    var serverUrl = elSetting.ServerUrl;
                    var minLevel = elSetting.MinimumLevel < param.MinimumLevel ? param.MinimumLevel : elSetting.MinimumLevel;
                    if (string.IsNullOrWhiteSpace(apiKey))
                    {
                        throw new ArgumentNullException("ExceptionLessSetting apiKey参数不能为空");
                    }
                    if (string.IsNullOrWhiteSpace(serverUrl))
                    {
                        throw new ArgumentNullException("ExceptionLessSetting serverUrl参数不能为空");
                    }
                    configuraton = configuraton.WriteTo.Exceptionless(apiKey, serverUrl: serverUrl, restrictedToMinimumLevel: minLevel);
                }
            }
            Serilog.Log.Logger = configuraton.CreateLogger();
        }
    }
}
